﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace IPAddressChecker
{
    /// <summary>
    /// Usage - 
    /// string this_variable_holds_the_IP_Address_Range_against_which_you_need_to_validate = "|192.168.1.3|192.58.22.*|192.168.1-7.*|192.32.*.*|192.23.22-87.45-*|";
    /// string visitors_ip_address = "192.168.1.3";
    /// bool is_my_ip_address_within_the_mentioned_range = clsIPAddressChecker.Check(this_variable_holds_the_IP_Address_Range_against_which_you_need_to_validate,my_ip_address,"|");
    /// if(is_my_ip_address_within_the_mentioned_range)
    /// {
    /// // Means My IP Address falls in the given IPAddressRange
    /// }
    /// else
    /// {
    /// // It Does not fall in the given IP Address range
    /// }
    /// </summary>
    public class IPAddressValidator
    {

        public bool Validate(string IPAddressRange, string VisitorsIPAddress, char Delimiter)
        {
            bool result = false;



            /* local vars */
            bool IsVisitorIPSixSegment = false;
            bool IsVisitorIPFourSegment = false;
            ArrayList RefinedFourSegmentIPRange = null;
            ArrayList RefinedSixSegmentIPRange = null;
            string Error = string.Empty;
            bool IsVisitorIPValid = false;
            bool IsIPAddressRangeValid = false;
            /* local vars ends*/

            IPAddressRange = IPAddressRange.TrimStart(Delimiter);
            IPAddressRange = IPAddressRange.TrimEnd(Delimiter);

            try
            {
                 IsVisitorIPValid = CheckIfIPValid(VisitorsIPAddress);
                 IsIPAddressRangeValid = CheckIfIPValid(IPAddressRange, Delimiter);
                

            }
            catch (Exception ex)
            {
                throw new ArgumentException("Either of the Arguments does not contain a Valid IPAddress /es");
            }


            if (!IsVisitorIPValid)
            {
                throw new ArgumentException("VisitorsIPAddress not a Valid IPAddress");
            }

            if (!IsIPAddressRangeValid)
            {
                throw new ArgumentException("IPAddressRange not a Valid IPAddress");
            }



            if (IsVisitorIPValid && IsIPAddressRangeValid)
            {


                if (VisitorsIPAddress.Split('.').Length == 6)
                {
                    IsVisitorIPSixSegment = true;
                    RefinedSixSegmentIPRange = new ArrayList();
                    ArrayList Temp = new ArrayList();

                    Temp.AddRange(IPAddressRange.Split(Delimiter));
                    foreach (string IP in Temp)
                    {
                        if (IP.Split('.').Length == 6)
                        {
                            RefinedSixSegmentIPRange.Add(IP);
                        }
                    }

                }
                else if (VisitorsIPAddress.Split('.').Length == 4)
                {
                    IsVisitorIPFourSegment = true;
                    RefinedFourSegmentIPRange = new ArrayList();
                    ArrayList Temp = new ArrayList();

                    Temp.AddRange(IPAddressRange.Split(Delimiter));
                    foreach (string IP in Temp)
                    {
                        if (IP.Split('.').Length == 4)
                        {
                            RefinedFourSegmentIPRange.Add(IP);
                        }
                    }
                }

                if (IsVisitorIPFourSegment)
                {
                    result = ValidateForFourSegment(RefinedFourSegmentIPRange, VisitorsIPAddress, out Error);
                }
                else if (IsVisitorIPSixSegment)
                {
                    result = ValidateForSixSegment(RefinedSixSegmentIPRange, VisitorsIPAddress, out Error);
                }
            }

            return result;
        }

        private bool ValidateForSixSegment(ArrayList IPRange, string VisitorsIPAddress, out string Error)
        {
            bool result = false;
            Error = string.Empty;

            string[] visitorsegment = VisitorsIPAddress.Split('.');
            foreach (string IP in IPRange)
            {
                int MatchCount = 0;

                if (IP.Contains('*'))
                {

                    string[] rangesegments = IP.Split('.');



                    for (int i = 0; i <= rangesegments.Length - 1; i++)  // segment fragmenting
                    {

                        if (rangesegments[i].Contains("-"))
                        {
                            int _segmentValue = Convert.ToInt32(visitorsegment[i]);
                            string[] temp = rangesegments[i].Split('-');


                            if (!temp.Contains("*"))
                            {
                                if (_segmentValue >= Convert.ToInt32(temp[0]) && _segmentValue <= Convert.ToInt32(temp[1]))
                                {
                                    MatchCount++;
                                }
                            }
                            else  // if * exists with - like 192.23.22-87.45-*
                            {

                                if (temp[0] == "*")
                                {
                                    MatchCount++;
                                }
                                else if (temp[1] == "*")
                                {
                                    if (_segmentValue >= Convert.ToInt32(temp[0]))
                                    {
                                        MatchCount++;
                                    }
                                }
                                else
                                {
                                    if ((_segmentValue >= Convert.ToInt32(temp[0])) && (_segmentValue <= Convert.ToInt32(temp[0])))
                                    {
                                        MatchCount++;
                                    }
                                }

                            }

                        }
                        else if (rangesegments[i] == "*")
                        {
                            MatchCount++;
                        }
                        else
                        {

                            if (visitorsegment[i] == rangesegments[i])
                            {
                                MatchCount++;
                            }
                        }
                    }


                }
                else
                {

                    if (IP == VisitorsIPAddress)
                    {
                        MatchCount = 4;
                        result = true;
                    }
                }

                if (6 == MatchCount)
                {
                    result = true;
                    break;
                }
            }

            return result;
        }

        private bool ValidateForFourSegment(ArrayList IPRange, string VisitorsIPAddress, out string Error)
        {
            bool result = false;
            Error = string.Empty;

            string[] visitorsegment = VisitorsIPAddress.Split('.');
            foreach (string IP in IPRange)
            {
                int MatchCount = 0;

                if (IP.Contains('*'))
                {

                    string[] rangesegments = IP.Split('.');



                    for (int i = 0; i <= rangesegments.Length - 1; i++)  // segment fragmenting
                    {

                        if (rangesegments[i].Contains("-"))
                        {
                            int _segmentValue = Convert.ToInt32(visitorsegment[i]);
                            string[] temp = rangesegments[i].Split('-');


                            if (!temp.Contains("*"))
                            {
                                if (_segmentValue >= Convert.ToInt32(temp[0]) && _segmentValue <= Convert.ToInt32(temp[1]))
                                {
                                    MatchCount++;
                                }
                            }
                            else  // if * exists with - like 192.23.22-87.45-*
                            {

                                if (temp[0] == "*")
                                {
                                    MatchCount++;
                                }
                                else if (temp[1] == "*")
                                {
                                    if (_segmentValue >= Convert.ToInt32(temp[0]))
                                    {
                                        MatchCount++;
                                    }
                                }
                                else
                                {
                                    if ((_segmentValue >= Convert.ToInt32(temp[0])) && (_segmentValue <= Convert.ToInt32(temp[0])))
                                    {
                                        MatchCount++;
                                    }
                                }

                            }

                        }
                        else if (rangesegments[i] == "*")
                        {
                            MatchCount++;
                        }
                        else
                        {

                            if (visitorsegment[i] == rangesegments[i])
                            {
                                MatchCount++;
                            }
                        }
                    }


                }
                else
                {

                    if (IP == VisitorsIPAddress)
                    {
                        MatchCount = 4;
                        result = true;
                    }
                }

                if (4 == MatchCount)
                {
                    result = true;
                    break;
                }
            }

            return result;
        }

        private bool CheckIfIPValid(string IPs, char delim = '\0')
        {
            bool result = false;

            /*local vars*/
            int OKIPCount = 0;
            int OKIPSegCount = 0;
            int ValidIPsCount = 0;
            /*local var ends*/

            if (delim == '\0') // visitor IP
            {
                result = IsSegmentBetweenValidRange(IPs);

            }
            else // IP Range
            {
                string[] multipleips = IPs.Split(delim);
                ValidIPsCount = multipleips.Length;

                foreach (string s in multipleips)
                {
                    if ((s.Contains('*')) || (s.Contains('-')))
                    {
                        string[] segments = s.Split('.');
                        OKIPSegCount = 0; // reset
                        foreach (string seg in segments)
                        {
                            if (seg.Contains('-'))
                            {
                                string[] temp = seg.Split('-');
                                if (temp[0] == "*")
                                {
                                    if ((int.Parse(temp[1]) >= 0) && (int.Parse(temp[1]) <= 255))
                                    {
                                        OKIPSegCount++;
                                    }
                                }
                                else if (temp[1] == "*")
                                {
                                    if ((int.Parse(temp[0]) >= 0) && (int.Parse(temp[0]) <= 255))
                                    {
                                        OKIPSegCount++;
                                    }
                                }
                                else
                                {
                                    if ((int.Parse(temp[0]) >= 0) && (int.Parse(temp[0]) <= 255))
                                    {
                                        if ((int.Parse(temp[1]) >= 0) && (int.Parse(temp[1]) <= 255))
                                        {
                                            OKIPSegCount++;
                                        }

                                    }
                                }

                            }
                            else if (seg.Contains('*'))
                            {
                                OKIPSegCount++;
                            }
                            else // number
                            {
                                if ((int.Parse(seg) >= 0) && (int.Parse(seg) <= 255))
                                {
                                    OKIPSegCount++;

                                }
                            }
                        }

                        if (OKIPSegCount == segments.Length)
                        {
                            OKIPCount++;
                        }
                    }
                    else
                    {
                        if (IsSegmentBetweenValidRange(s))
                        {
                            OKIPCount++;
                        }
                    }

                   
                }

                if (OKIPCount == ValidIPsCount)
                {
                    result = true;
                }
                //string[] visitorsegment = IPs.Split(delim);
            }

            return result;
        }

        private bool IsSegmentBetweenValidRange(string IP)
        {
            bool result = false;

            /*local var*/

            int OKCount = 0;
            int ValidCount = 0;

            if (IP.Split('.').Length == 4)
            {
                ValidCount = 4;
            }
            else if (IP.Split('.').Length == 6)
            {
                ValidCount = 6;
            }
            else
            {

            }


            /*local var ends*/
            foreach (string s in IP.Split('.'))
            {
                try
                {
                    if ((int.Parse(s) >= 0) && (int.Parse(s) <= 255))
                    {
                        OKCount++;
                    }
                }
                catch (Exception ex)
                {

                }

            }

            if (OKCount == ValidCount)
            {
                result = true;
            }


            return result;
        }
    }
}
